﻿using System;
using System.Runtime.InteropServices;

namespace Microsoft.Xna.Framework
{
    /// <summary>
    /// Defines a matrix.
    /// </summary>
    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public struct Matrix : IEquatable<Matrix>
    {
        #region Public Fields
        public float M11;
        public float M12;
        public float M13;
        public float M14;
        public float M21;
        public float M22;
        public float M23;
        public float M24;
        public float M31;
        public float M32;
        public float M33;
        public float M34;
        public float M41;
        public float M42;
        public float M43;
        public float M44;
        #endregion

        #region Constructor
        /// <summary>
        /// Initializes a new instance of Matrix.
        /// </summary>
        /// <param name="m11">Value to initialize m11 to.</param>
        /// <param name="m12">Value to initialize m12 to.</param>
        /// <param name="m13">Value to initialize m13 to.</param>
        /// <param name="m14">Value to initialize m14 to.</param>
        /// <param name="m21">Value to initialize m21 to.</param>
        /// <param name="m22">Value to initialize m22 to.</param>
        /// <param name="m23">Value to initialize m23 to.</param>
        /// <param name="m24">Value to initialize m24 to.</param>
        /// <param name="m31">Value to initialize m31 to.</param>
        /// <param name="m32">Value to initialize m32 to.</param>
        /// <param name="m33">Value to initialize m33 to.</param>
        /// <param name="m34">Value to initialize m34 to.</param>
        /// <param name="m41">Value to initialize m41 to.</param>
        /// <param name="m42">Value to initialize m42 to.</param>
        /// <param name="m43">Value to initialize m43 to.</param>
        /// <param name="m44">Value to initialize m44 to.</param>
        public Matrix(float m11, float m12, float m13, float m14, float m21, float m22, float m23, float m24, float m31,
            float m32, float m33, float m34, float m41, float m42, float m43, float m44)
        {
            M11 = m11;
            M12 = m12;
            M13 = m13;
            M14 = m14;
            M21 = m21;
            M22 = m22;
            M23 = m23;
            M24 = m24;
            M31 = m31;
            M32 = m32;
            M33 = m33;
            M34 = m34;
            M41 = m41;
            M42 = m42;
            M43 = m43;
            M44 = m44;
        }
        #endregion

        #region Properties
        /// <summary>
        /// Gets and sets the backward vector of the Matrix.
        /// </summary>
        public Vector3 Backward
        {
            get { return new Vector3(M31, M32, M33); }
            set { M31 = value.X; M32 = value.Y; M33 = value.Z; }
        }
        /// <summary>
        /// Gets and sets the down vector of the Matrix.
        /// </summary>
        public Vector3 Down
        {
            get { return new Vector3(-this.M21, -this.M22, -this.M23); }
            set { M21 = -value.X; M22 = -value.Y; M23 = -value.Z; }
        }
        /// <summary>
        /// Gets and sets the forward vector of the Matrix.
        /// </summary>
        public Vector3 Forward
        {
            get { return new Vector3(-M31, -M32, -M33); }
            set { M31 = -value.X; M32 = -value.Y; M33 = -value.Z; }
        }
        /// <summary>
        /// Returns an instance of the identity matrix.
        /// </summary>
        public static Matrix Identity
        {
            get { return new Matrix(1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f); }
        }
        /// <summary>
        /// Gets and sets the left vector of the Matrix.
        /// </summary>
        public Vector3 Left
        {
            get { return new Vector3(-M11, -M12, -M13); }
            set { M11 = -value.X; M12 = -value.Y; M13 = -value.Z; }
        }
        /// <summary>
        /// Gets and sets the right vector of the Matrix.
        /// </summary>
        public Vector3 Right
        {
            get { return new Vector3(M11, M12, M13); }
            set { M11 = value.X; M12 = value.Y; M13 = value.Z; }
        }
        /// <summary>
        /// Gets and sets the translation vector of the Matrix.
        /// </summary>
        public Vector3 Translation
        {
            get { return new Vector3(M41, M42, M43); }
            set { M41 = value.X; M42 = value.Y; M43 = value.Z; }
        }
        /// <summary>
        /// Gets and sets the up vector of the Matrix.
        /// </summary>
        public Vector3 Up
        {
            get { return new Vector3(M21, M22, M23); }
            set { M21 = value.X; M22 = value.Y; M23 = value.Z; }
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Adds a matrix to another matrix.
        /// </summary>
        /// <param name="matrix1">Source matrix.</param>
        /// <param name="matrix2">Source matrix.</param>
        /// <param name="result">Resulting matrix.</param>
        public static void Add(ref Matrix matrix1, ref Matrix matrix2, out Matrix result)
        {
            result.M11 = matrix1.M11 + matrix2.M11;
            result.M12 = matrix1.M12 + matrix2.M12;
            result.M13 = matrix1.M13 + matrix2.M13;
            result.M14 = matrix1.M14 + matrix2.M14;
            result.M21 = matrix1.M21 + matrix2.M21;
            result.M22 = matrix1.M22 + matrix2.M22;
            result.M23 = matrix1.M23 + matrix2.M23;
            result.M24 = matrix1.M24 + matrix2.M24;
            result.M31 = matrix1.M31 + matrix2.M31;
            result.M32 = matrix1.M32 + matrix2.M32;
            result.M33 = matrix1.M33 + matrix2.M33;
            result.M34 = matrix1.M34 + matrix2.M34;
            result.M41 = matrix1.M41 + matrix2.M41;
            result.M42 = matrix1.M42 + matrix2.M42;
            result.M43 = matrix1.M43 + matrix2.M43;
            result.M44 = matrix1.M44 + matrix2.M44;
        }
        /// <summary>
        /// Adds a matrix to another matrix.
        /// </summary>
        /// <param name="matrix1">Source matrix.</param>
        /// <param name="matrix2">Source matrix.</param>
        public static Matrix Add(Matrix matrix1, Matrix matrix2)
        {
            matrix1.M11 += matrix2.M11;
            matrix1.M12 += matrix2.M12;
            matrix1.M13 += matrix2.M13;
            matrix1.M14 += matrix2.M14;
            matrix1.M21 += matrix2.M21;
            matrix1.M22 += matrix2.M22;
            matrix1.M23 += matrix2.M23;
            matrix1.M24 += matrix2.M24;
            matrix1.M31 += matrix2.M31;
            matrix1.M32 += matrix2.M32;
            matrix1.M33 += matrix2.M33;
            matrix1.M34 += matrix2.M34;
            matrix1.M41 += matrix2.M41;
            matrix1.M42 += matrix2.M42;
            matrix1.M43 += matrix2.M43;
            matrix1.M44 += matrix2.M44;
            return matrix1;
        }
        /// <summary>
        /// Creates a spherical billboard that rotates around a specified object position.
        /// </summary>
        /// <param name="objectPosition">Position of the object the billboard will rotate around.</param>
        /// <param name="cameraPosition">Position of the camera.</param>
        /// <param name="cameraUpVector">The up vector of the camera.</param>
        /// <param name="cameraForwardVector">Optional forward vector of the camera.</param>
        /// <param name="result">The created billboard matrix.</param>
        public static void CreateBillboard(ref Vector3 objectPosition, ref Vector3 cameraPosition,
            ref Vector3 cameraUpVector, Vector3? cameraForwardVector, out Matrix result)
        {
            Vector3 translation = objectPosition - cameraPosition;
            Vector3 backwards, right, up;
            Vector3.Normalize(ref translation, out backwards);
            Vector3.Normalize(ref cameraUpVector, out up);
            Vector3.Cross(ref backwards, ref up, out right);
            Vector3.Cross(ref backwards, ref right, out up);
            result = Matrix.Identity;
            result.Backward = backwards;
            result.Right = right;
            result.Up = up;
            result.Translation = translation; 
        }
        /// <summary>
        /// Creates a spherical billboard that rotates around a specified object position.
        /// </summary>
        /// <param name="objectPosition">Position of the object the billboard will rotate around.</param>
        /// <param name="cameraPosition">Position of the camera.</param>
        /// <param name="cameraUpVector">The up vector of the camera.</param>
        /// <param name="cameraForwardVector">Optional forward vector of the camera.</param>
        public static Matrix CreateBillboard(Vector3 objectPosition, Vector3 cameraPosition,
            Vector3 cameraUpVector, Nullable<Vector3> cameraForwardVector)
        {
            Matrix result;
            Vector3 translation = objectPosition - cameraPosition;
            Vector3 backwards, right, up;
            Vector3.Normalize(ref translation, out backwards);
            Vector3.Normalize(ref cameraUpVector, out up);
            Vector3.Cross(ref backwards, ref up, out right);
            Vector3.Cross(ref backwards, ref right, out up);
            result = Matrix.Identity;
            result.Backward = backwards;
            result.Right = right;
            result.Up = up;
            result.Translation = translation; 
  
            return result; 
        }
        /// <summary>
        /// Creates a cylindrical billboard that rotates around a specified axis.
        /// </summary>
        /// <param name="objectPosition">Position of the object the billboard will rotate around.</param>
        /// <param name="cameraPosition">Position of the camera.</param>
        /// <param name="rotateAxis">Axis to rotate the billboard around.</param>
        /// <param name="cameraForwardVector">Optional forward vector of the camera.</param>
        /// <param name="objectForwardVector">Optional forward vector of the object.</param>
        /// <param name="result">The created billboard matrix.</param>
        public static void CreateConstrainedBillboard(ref Vector3 objectPosition, ref Vector3 cameraPosition,
             ref Vector3 rotateAxis, Vector3? cameraForwardVector, Vector3? objectForwardVector, out Matrix result)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Creates a cylindrical billboard that rotates around a specified axis.
        /// </summary>
        /// <param name="objectPosition">Position of the object the billboard will rotate around.</param>
        /// <param name="cameraPosition">Position of the camera.</param>
        /// <param name="rotateAxis">Axis to rotate the billboard around.</param>
        /// <param name="cameraForwardVector">Optional forward vector of the camera.</param>
        /// <param name="objectForwardVector">Optional forward vector of the object.</param>
        public static Matrix CreateConstrainedBillboard(Vector3 objectPosition, Vector3 cameraPosition,
             Vector3 rotateAxis, Nullable<Vector3> cameraForwardVector, Nullable<Vector3> objectForwardVector)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Creates a new Matrix that rotates around an arbitrary vector.
        /// </summary>
        /// <param name="axis">The axis to rotate around.</param>
        /// <param name="angle">The angle to rotate around the vector.</param>
        /// <param name="result">The created matrix.</param>
        public static void CreateFromAxisAngle(ref Vector3 axis, float angle, out Matrix result)
        {
            if (axis.LengthSquared() != 1.0f)
                axis.Normalize();

            float x = axis.X;
            float y = axis.Y;
            float z = axis.Z;
            float cos = (float)Math.Cos(angle);
            float sin = (float)Math.Sin(angle);
            float xx = x * x;
            float yy = y * y;
            float zz = z * z;
            float xy = x * y;
            float xz = x * z;
            float yz = y * z;

            result.M11 = xx + (cos * (1.0f - xx));
            result.M12 = (xy - (cos * xy)) + (sin * z);
            result.M13 = (xz - (cos * xz)) - (sin * y);
            result.M14 = 0.0f;
            result.M21 = (xy - (cos * xy)) - (sin * z);
            result.M22 = yy + (cos * (1.0f - yy));
            result.M23 = (yz - (cos * yz)) + (sin * x);
            result.M24 = 0.0f;
            result.M31 = (xz - (cos * xz)) + (sin * y);
            result.M32 = (yz - (cos * yz)) - (sin * x);
            result.M33 = zz + (cos * (1.0f - zz));
            result.M34 = 0.0f;
            result.M41 = 0.0f;
            result.M42 = 0.0f;
            result.M43 = 0.0f;
            result.M44 = 1.0f;
        }
        /// <summary>
        /// Creates a new Matrix that rotates around an arbitrary vector.
        /// </summary>
        /// <param name="axis">The axis to rotate around.</param>
        /// <param name="angle">The angle to rotate around the vector.</param>
        public static Matrix CreateFromAxisAngle(Vector3 axis, float angle)
        {
            if( axis.LengthSquared() != 1.0f ) 
                axis.Normalize(); 
  
            Matrix result; 
            float x = axis.X; 
            float y = axis.Y; 
            float z = axis.Z; 
            float cos = (float)Math.Cos(angle); 
            float sin = (float)Math.Sin(angle); 
            float xx = x * x; 
            float yy = y * y; 
            float zz = z * z; 
            float xy = x * y; 
            float xz = x * z; 
            float yz = y * z; 
  
            result.M11 = xx + (cos * (1.0f - xx)); 
            result.M12 = (xy - (cos * xy)) + (sin * z); 
            result.M13 = (xz - (cos * xz)) - (sin * y); 
            result.M14 = 0.0f; 
            result.M21 = (xy - (cos * xy)) - (sin * z); 
            result.M22 = yy + (cos * (1.0f - yy)); 
            result.M23 = (yz - (cos * yz)) + (sin * x); 
            result.M24 = 0.0f; 
            result.M31 = (xz - (cos * xz)) + (sin * y); 
            result.M32 = (yz - (cos * yz)) - (sin * x); 
            result.M33 = zz + (cos * (1.0f - zz)); 
            result.M34 = 0.0f; 
            result.M41 = 0.0f; 
            result.M42 = 0.0f; 
            result.M43 = 0.0f; 
            result.M44 = 1.0f; 
  
            return result; 
        }
        /// <summary>
        /// Creates a rotation Matrix from a Quaternion.
        /// </summary>
        /// <param name="quaternion">Quaternion to create the Matrix from.</param>
        /// <param name="result">The created Matrix.</param>
        public static void CreateFromQuaternion(ref Quaternion quaternion, out Matrix result)
        {
            float xx = quaternion.X * quaternion.X;
            float yy = quaternion.Y * quaternion.Y;
            float zz = quaternion.Z * quaternion.Z;
            float xy = quaternion.X * quaternion.Y;
            float zw = quaternion.Z * quaternion.W;
            float zx = quaternion.Z * quaternion.X;
            float yw = quaternion.Y * quaternion.W;
            float yz = quaternion.Y * quaternion.Z;
            float xw = quaternion.X * quaternion.W;
            result.M11 = 1.0f - (2.0f * (yy + zz));
            result.M12 = 2.0f * (xy + zw);
            result.M13 = 2.0f * (zx - yw);
            result.M14 = 0.0f;
            result.M21 = 2.0f * (xy - zw);
            result.M22 = 1.0f - (2.0f * (zz + xx));
            result.M23 = 2.0f * (yz + xw);
            result.M24 = 0.0f;
            result.M31 = 2.0f * (zx + yw);
            result.M32 = 2.0f * (yz - xw);
            result.M33 = 1.0f - (2.0f * (yy + xx));
            result.M34 = 0.0f;
            result.M41 = 0.0f;
            result.M42 = 0.0f;
            result.M43 = 0.0f;
            result.M44 = 1.0f; 
        }
        /// <summary>
        /// Creates a rotation Matrix from a Quaternion.
        /// </summary>
        /// <param name="quaternion">Quaternion to create the Matrix from.</param>
        public static Matrix CreateFromQuaternion(Quaternion quaternion)
        {
            Matrix result;
            float xx = quaternion.X * quaternion.X;
            float yy = quaternion.Y * quaternion.Y;
            float zz = quaternion.Z * quaternion.Z;
            float xy = quaternion.X * quaternion.Y;
            float zw = quaternion.Z * quaternion.W;
            float zx = quaternion.Z * quaternion.X;
            float yw = quaternion.Y * quaternion.W;
            float yz = quaternion.Y * quaternion.Z;
            float xw = quaternion.X * quaternion.W;
            result.M11 = 1.0f - (2.0f * (yy + zz));
            result.M12 = 2.0f * (xy + zw);
            result.M13 = 2.0f * (zx - yw);
            result.M14 = 0.0f;
            result.M21 = 2.0f * (xy - zw);
            result.M22 = 1.0f - (2.0f * (zz + xx));
            result.M23 = 2.0f * (yz + xw);
            result.M24 = 0.0f;
            result.M31 = 2.0f * (zx + yw);
            result.M32 = 2.0f * (yz - xw);
            result.M33 = 1.0f - (2.0f * (yy + xx));
            result.M34 = 0.0f;
            result.M41 = 0.0f;
            result.M42 = 0.0f;
            result.M43 = 0.0f;
            result.M44 = 1.0f;
            return result;
        }
        /// <summary>
        /// Fills in a rotation matrix from a specified yaw, pitch, and roll.
        /// </summary>
        /// <param name="yaw">Angle of rotation, in radians, around the y-axis.</param>
        /// <param name="pitch">Angle of rotation, in radians, around the x-axis.</param>
        /// <param name="roll">Angle of rotation, in radians, around the z-axis.</param>
        /// <param name="result">An existing matrix filled in to represent the specified yaw, pitch, and roll.</param>
        public static void CreateFromYawPitchRoll(float yaw, float pitch, float roll, out Matrix result)
        {
            Quaternion quaternion;
            Quaternion.CreateFromYawPitchRoll(yaw, pitch, roll, out quaternion);
            CreateFromQuaternion(ref quaternion, out result);
        }
        /// <summary>
        /// Fills in a rotation matrix from a specified yaw, pitch, and roll.
        /// </summary>
        /// <param name="yaw">Angle of rotation, in radians, around the y-axis.</param>
        /// <param name="pitch">Angle of rotation, in radians, around the x-axis.</param>
        /// <param name="roll">Angle of rotation, in radians, around the z-axis.</param>
        public static Matrix CreateFromYawPitchRoll(float yaw, float pitch, float roll)
        {
            Matrix matrix;
            Quaternion quaternion;
            Quaternion.CreateFromYawPitchRoll(yaw, pitch, roll, out quaternion);
            CreateFromQuaternion(ref quaternion, out matrix);
            return matrix;
        }
        /// <summary>
        /// Creates a view matrix.
        /// </summary>
        /// <param name="cameraPosition">The position of the camera.</param>
        /// <param name="cameraTarget">The target towards which the camera is pointing.</param>
        /// <param name="cameraUpVector">The direction that is "up" from the camera's point of view.</param>
        /// <param name="result">The created view matrix.</param>
        public static void CreateLookAt(ref Vector3 cameraPosition, ref Vector3 cameraTarget, ref Vector3 cameraUpVector, out Matrix result)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Creates a view matrix.
        /// </summary>
        /// <param name="cameraPosition">The position of the camera.</param>
        /// <param name="cameraTarget">The target towards which the camera is pointing.</param>
        /// <param name="cameraUpVector">The direction that is "up" from the camera's point of view.</param>
        public static Matrix CreateLookAt(Vector3 cameraPosition, Vector3 cameraTarget, Vector3 cameraUpVector)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Builds an orthogonal projection matrix.
        /// </summary>
        /// <param name="width">Width of the view volume.</param>
        /// <param name="height">Height of the view volume.</param>
        /// <param name="zNearPlane">Minimum z-value of the view volume.</param>
        /// <param name="zFarPlane">Maximum z-value of the view volume.</param>
        /// <param name="result">The projection matrix.</param>
        public static void CreateOrthographic(float width, float height, float zNearPlane, float zFarPlane, out Matrix result)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Builds an orthogonal projection matrix.
        /// </summary>
        /// <param name="width">Width of the view volume.</param>
        /// <param name="height">Height of the view volume.</param>
        /// <param name="zNearPlane">Minimum z-value of the view volume.</param>
        /// <param name="zFarPlane">Maximum z-value of the view volume.</param>
        public static Matrix CreateOrthographic(float width, float height, float zNearPlane, float zFarPlane)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Builds a customized, orthogonal projection matrix.
        /// </summary>
        /// <param name="left">Minimum x-value of the view volume.</param>
        /// <param name="right">Maximum x-value of the view volume.</param>
        /// <param name="bottom">Minimum y-value of the view volume.</param>
        /// <param name="top">Maximum y-value of the view volume.</param>
        /// <param name="zNearPlane">Minimum z-value of the view volume.</param>
        /// <param name="zFarPlane">Maximum z-value of the view volume.</param>
        /// <param name="result">The projection matrix.</param>
        public static void CreateOrthographicOffCenter(float left, float right, float bottom, float top,
             float zNearPlane, float zFarPlane, out Matrix result)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Builds a customized, orthogonal projection matrix.
        /// </summary>
        /// <param name="left">Minimum x-value of the view volume.</param>
        /// <param name="right">Maximum x-value of the view volume.</param>
        /// <param name="bottom">Minimum y-value of the view volume.</param>
        /// <param name="top">Maximum y-value of the view volume.</param>
        /// <param name="zNearPlane">Minimum z-value of the view volume.</param>
        /// <param name="zFarPlane">Maximum z-value of the view volume.</param>
        public static Matrix CreateOrthographicOffCenter(float left, float right, float bottom, float top, float zNearPlane, float zFarPlane)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Builds a perspective projection matrix.
        /// </summary>
        /// <param name="width">Width of the view volume at the near view plane.</param>
        /// <param name="height">Height of the view volume at the near view plane.</param>
        /// <param name="zNearPlane">Distance to the near view plane.</param>
        /// <param name="zFarPlane">Distance to the far view plane.</param>
        /// <param name="result">The projection matrix.</param>
        public static void CreatePerspective(float width, float height, float zNearPlane, float zFarPlane, out Matrix result)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Builds a perspective projection matrix.
        /// </summary>
        /// <param name="width">Width of the view volume at the near view plane.</param>
        /// <param name="height">Height of the view volume at the near view plane.</param>
        /// <param name="zNearPlane">Distance to the near view plane.</param>
        /// <param name="zFarPlane">Distance to the far view plane.</param>
        public static Matrix CreatePerspective(float width, float height, float zNearPlane, float zFarPlane)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Builds a perspective projection matrix based on a field of view.
        /// </summary>
        /// <param name="fieldOfView">Field of view in radians.</param>
        /// <param name="aspectRatio">Aspect ratio, defined as view space width divided by height.</param>
        /// <param name="nearPlaneDistance">Distance to the near view plane.</param>
        /// <param name="farPlaneDistance">Distance to the far view plane.</param>
        /// <param name="result">The perspective projection matrix.</param>
        public static void CreatePerspectiveFieldOfView(float fieldOfView, float aspectRatio, float nearPlaneDistance, float farPlaneDistance, out Matrix result)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Builds a perspective projection matrix based on a field of view.
        /// </summary>
        /// <param name="fieldOfView">Field of view in radians.</param>
        /// <param name="aspectRatio">Aspect ratio, defined as view space width divided by height.</param>
        /// <param name="zNearPlane">Distance to the near view plane.</param>
        /// <param name="zFarPlane">Distance to the far view plane.</param>
        public static Matrix CreatePerspectiveFieldOfView(float fieldOfView, float aspectRatio, float zNearPlane, float zFarPlane)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Builds a customized, perspective projection matrix.
        /// </summary>
        /// <param name="left">Minimum x-value of the view volume at the near view plane.</param>
        /// <param name="right">Maximum x-value of the view volume at the near view plane.</param>
        /// <param name="bottom">Minimum y-value of the view volume at the near view plane.</param>
        /// <param name="top">Maximum y-value of the view volume at the near view plane.</param>
        /// <param name="nearPlaneDistance">Distance to the near view plane.</param>
        /// <param name="farPlaneDistance">Distance to of the far view plane.</param>
        /// <param name="result">The created projection matrix.</param>
        public static void CreatePerspectiveOffCenter(float left, float right, float bottom, float top, float nearPlaneDistance, float farPlaneDistance, out Matrix result)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Builds a customized, perspective projection matrix.
        /// </summary>
        /// <param name="left">Minimum x-value of the view volume at the near view plane.</param>
        /// <param name="right">Maximum x-value of the view volume at the near view plane.</param>
        /// <param name="bottom">Minimum y-value of the view volume at the near view plane.</param>
        /// <param name="top">Maximum y-value of the view volume at the near view plane.</param>
        /// <param name="zNearPlane">Distance to the near view plane.</param>
        /// <param name="zFarPlane">Distance to of the far view plane.</param>
        public static Matrix CreatePerspectiveOffCenter(float left, float right, float bottom, float top, float zNearPlane, float zFarPlane)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Fills in an existing Matrix so that it reflects the coordinate system about a specified Plane.
        /// </summary>
        /// <param name="value">The Plane about which to create a reflection.</param>
        /// <param name="result">A Matrix that creates the reflection.</param>
        public static void CreateReflection(ref Plane value, out Matrix result)
        {
            value.Normalize();
            float x = value.Normal.X;
            float y = value.Normal.Y;
            float z = value.Normal.Z;
            float x2 = -2.0f * x;
            float y2 = -2.0f * y;
            float z2 = -2.0f * z;
            result.M11 = (x2 * x) + 1.0f;
            result.M12 = y2 * x;
            result.M13 = z2 * x;
            result.M14 = 0.0f;
            result.M21 = x2 * y;
            result.M22 = (y2 * y) + 1.0f;
            result.M23 = z2 * y;
            result.M24 = 0.0f;
            result.M31 = x2 * z;
            result.M32 = y2 * z;
            result.M33 = (z2 * z) + 1.0f;
            result.M34 = 0.0f;
            result.M41 = x2 * value.D;
            result.M42 = y2 * value.D;
            result.M43 = z2 * value.D;
            result.M44 = 1.0f; 
        }
        /// <summary>
        /// Fills in an existing Matrix so that it reflects the coordinate system about a specified Plane.
        /// </summary>
        /// <param name="value">The Plane about which to create a reflection.</param>
        public static Matrix CreateReflection(Plane value)
        {
            Matrix result;
            value.Normalize();
            float x = value.Normal.X;
            float y = value.Normal.Y;
            float z = value.Normal.Z;
            float x2 = -2.0f * x;
            float y2 = -2.0f * y;
            float z2 = -2.0f * z;
            result.M11 = (x2 * x) + 1.0f;
            result.M12 = y2 * x;
            result.M13 = z2 * x;
            result.M14 = 0.0f;
            result.M21 = x2 * y;
            result.M22 = (y2 * y) + 1.0f;
            result.M23 = z2 * y;
            result.M24 = 0.0f;
            result.M31 = x2 * z;
            result.M32 = y2 * z;
            result.M33 = (z2 * z) + 1.0f;
            result.M34 = 0.0f;
            result.M41 = x2 * value.D;
            result.M42 = y2 * value.D;
            result.M43 = z2 * value.D;
            result.M44 = 1.0f;
            return result;
        }
        /// <summary>
        /// Returns a matrix that can be used to rotate a set of vertices around the x-axis.
        /// </summary>
        /// <param name="radians">The amount, in radians, in which to rotate around the x-axis. Note that you can use ToRadians to convert degrees to radians.</param>
        /// <param name="result">The matrix in which to place the calculated data.</param>
        public static void CreateRotationX(float radians, out Matrix result)
        {
            result = Matrix.Identity;

            result.M22 = (float)Math.Cos(radians);
            result.M23 = (float)Math.Sin(radians);
            result.M32 = -result.M23;
            result.M33 = result.M22;
        }
        /// <summary>
        /// Populates data into a user-specified matrix that can be used to rotate a set of vertices around the x-axis.
        /// </summary>
        /// <param name="radians">The amount, in radians, in which to rotate around the x-axis. Note that you can use ToRadians to convert degrees to radians.</param>
        public static Matrix CreateRotationX(float radians)
        {
            Matrix returnMatrix = Matrix.Identity;

            returnMatrix.M22 = (float)Math.Cos(radians);
            returnMatrix.M23 = (float)Math.Sin(radians);
            returnMatrix.M32 = -returnMatrix.M23;
            returnMatrix.M33 = returnMatrix.M22;

            return returnMatrix;
        }
        /// <summary>
        /// Populates data into a user-specified matrix that can be used to rotate a set of vertices around the y-axis.
        /// </summary>
        /// <param name="radians">The amount, in radians, in which to rotate around the y-axis. Note that you can use ToRadians to convert degrees to radians.</param>
        /// <param name="result">The matrix in which to place the calculated data.</param>
        public static void CreateRotationY(float radians, out Matrix result)
        {
            result = Matrix.Identity;

            result.M11 = (float)Math.Cos(radians);
            result.M13 = (float)Math.Sin(radians);
            result.M31 = -result.M13;
            result.M33 = result.M11;
        }
        /// <summary>
        /// Returns a matrix that can be used to rotate a set of vertices around the y-axis.
        /// </summary>
        /// <param name="radians">The amount, in radians, in which to rotate around the y-axis. Note that you can use ToRadians to convert degrees to radians.</param>
        public static Matrix CreateRotationY(float radians)
        {
            Matrix returnMatrix = Matrix.Identity;

            returnMatrix.M11 = (float)Math.Cos(radians);
            returnMatrix.M13 = (float)Math.Sin(radians);
            returnMatrix.M31 = -returnMatrix.M13;
            returnMatrix.M33 = returnMatrix.M11;

            return returnMatrix;
        }
        /// <summary>
        /// Populates data into a user-specified matrix that can be used to rotate a set of vertices around the z-axis.
        /// </summary>
        /// <param name="radians">The amount, in radians, in which to rotate around the z-axis. Note that you can use ToRadians to convert degrees to radians.</param>
        /// <param name="result">The rotation matrix.</param>
        public static void CreateRotationZ(float radians, out Matrix result)
        {
            result = Matrix.Identity;

            result.M11 = (float)Math.Cos(radians);
            result.M12 = (float)Math.Sin(radians);
            result.M21 = -result.M12;
            result.M22 = result.M11;
        }
        /// <summary>
        /// Returns a matrix that can be used to rotate a set of vertices around the z-axis.
        /// </summary>
        /// <param name="radians">The amount, in radians, in which to rotate around the z-axis. Note that you can use ToRadians to convert degrees to radians.</param>
        public static Matrix CreateRotationZ(float radians)
        {
            Matrix returnMatrix = Matrix.Identity;

            returnMatrix.M11 = (float)Math.Cos(radians);
            returnMatrix.M12 = (float)Math.Sin(radians);
            returnMatrix.M21 = -returnMatrix.M12;
            returnMatrix.M22 = returnMatrix.M11;

            return returnMatrix;
        }
        /// <summary>
        /// Creates a scaling Matrix.
        /// </summary>
        /// <param name="scale">Value to scale by.</param>
        /// <param name="result">The created scaling Matrix.</param>
        public static void CreateScale(float scale, out Matrix result)
        {
            result = Matrix.Identity;

            result.M11 = scale;
            result.M22 = scale;
            result.M33 = scale;
        }
        /// <summary>
        /// Creates a scaling Matrix.
        /// </summary>
        /// <param name="scale">Value to scale by.</param>
        public static Matrix CreateScale(float scale)
        {
            Matrix returnMatrix = Matrix.Identity;

            returnMatrix.M11 = scale;
            returnMatrix.M22 = scale;
            returnMatrix.M33 = scale;

            return returnMatrix;
        }
        /// <summary>
        /// Creates a scaling Matrix.
        /// </summary>
        /// <param name="scales">Amounts to scale by on the x, y, and z axes.</param>
        /// <param name="result">The created scaling Matrix.</param>
        public static void CreateScale(ref Vector3 scales, out Matrix result)
        {
            result = Matrix.Identity;

            result.M11 = scales.X;
            result.M22 = scales.Y;
            result.M33 = scales.Z;
        }
        /// <summary>
        /// Creates a scaling Matrix.
        /// </summary>
        /// <param name="scales">Amounts to scale by on the x, y, and z axes.</param>
        public static Matrix CreateScale(Vector3 scales)
        {
            Matrix returnMatrix = Matrix.Identity;

            returnMatrix.M11 = scales.X;
            returnMatrix.M22 = scales.Y;
            returnMatrix.M33 = scales.Z;

            return returnMatrix;
        } 
        /// <summary>
        /// Creates a scaling Matrix.
        /// </summary>
        /// <param name="xScale">Value to scale by on the x-axis.</param>
        /// <param name="yScale">Value to scale by on the y-axis.</param>
        /// <param name="zScale">Value to scale by on the z-axis.</param>
        /// <param name="result">The created scaling Matrix.</param>
        public static void CreateScale(float xScale, float yScale, float zScale, out Matrix result)
        {
            result = Matrix.Identity;

            result.M11 = xScale;
            result.M22 = yScale;
            result.M33 = zScale;
        }
        /// <summary>
        /// Creates a scaling Matrix.
        /// </summary>
        /// <param name="xScale">Value to scale by on the x-axis.</param>
        /// <param name="yScale">Value to scale by on the y-axis.</param>
        /// <param name="zScale">Value to scale by on the z-axis.</param>
        public static Matrix CreateScale(float xScale, float yScale, float zScale)
        {
            Matrix returnMatrix = Matrix.Identity;

            returnMatrix.M11 = xScale;
            returnMatrix.M22 = yScale;
            returnMatrix.M33 = zScale;

            return returnMatrix;
        }
        /// <summary>
        /// Fills in a Matrix to flatten geometry into a specified Plane as if casting a shadow from a specified light source.
        /// </summary>
        /// <param name="lightDirection">A Vector3 specifying the direction from which the light that will cast the shadow is coming.</param>
        /// <param name="plane">The Plane onto which the new matrix should flatten geometry so as to cast a shadow.</param>
        /// <param name="result">A Matrix that can be used to flatten geometry onto the specified plane from the specified direction.</param>
        public static void CreateShadow(ref Vector3 lightDirection, ref Plane plane, out Matrix result)
        {
            plane.Normalize();
            float dot = ((plane.Normal.X * lightDirection.X) + (plane.Normal.Y * lightDirection.Y)) + (plane.Normal.Z * lightDirection.Z);
            float x = -plane.Normal.X;
            float y = -plane.Normal.Y;
            float z = -plane.Normal.Z;
            float d = -plane.D;
            result.M11 = (x * lightDirection.X) + dot;
            result.M21 = y * lightDirection.X;
            result.M31 = z * lightDirection.X;
            result.M41 = d * lightDirection.X;
            result.M12 = x * lightDirection.Y;
            result.M22 = (y * lightDirection.Y) + dot;
            result.M32 = z * lightDirection.Y;
            result.M42 = d * lightDirection.Y;
            result.M13 = x * lightDirection.Z;
            result.M23 = y * lightDirection.Z;
            result.M33 = (z * lightDirection.Z) + dot;
            result.M43 = d * lightDirection.Z;
            result.M14 = 0.0f;
            result.M24 = 0.0f;
            result.M34 = 0.0f;
            result.M44 = dot; 
        }
        /// <summary>
        /// Creates a Matrix that flattens geometry into a specified Plane as if casting a shadow from a specified light source.
        /// </summary>
        /// <param name="lightDirection">A Vector3 specifying the direction from which the light that will cast the shadow is coming.</param>
        /// <param name="plane">The Plane onto which the new matrix should flatten geometry so as to cast a shadow.</param>
        public static Matrix CreateShadow(Vector3 lightDirection, Plane plane)
        {
            Matrix result;
            plane.Normalize();
            float dot = ((plane.Normal.X * lightDirection.X) + (plane.Normal.Y * lightDirection.Y)) + (plane.Normal.Z * lightDirection.Z);
            float x = -plane.Normal.X;
            float y = -plane.Normal.Y;
            float z = -plane.Normal.Z;
            float d = -plane.D;
            result.M11 = (x * lightDirection.X) + dot;
            result.M21 = y * lightDirection.X;
            result.M31 = z * lightDirection.X;
            result.M41 = d * lightDirection.X;
            result.M12 = x * lightDirection.Y;
            result.M22 = (y * lightDirection.Y) + dot;
            result.M32 = z * lightDirection.Y;
            result.M42 = d * lightDirection.Y;
            result.M13 = x * lightDirection.Z;
            result.M23 = y * lightDirection.Z;
            result.M33 = (z * lightDirection.Z) + dot;
            result.M43 = d * lightDirection.Z;
            result.M14 = 0.0f;
            result.M24 = 0.0f;
            result.M34 = 0.0f;
            result.M44 = dot;
            return result;
        }
        /// <summary>
        /// Creates a translation Matrix.
        /// </summary>
        /// <param name="xPosition">Value to translate by on the x-axis.</param>
        /// <param name="yPosition">Value to translate by on the y-axis.</param>
        /// <param name="zPosition">Value to translate by on the z-axis.</param>
        /// <param name="result">The created translation Matrix.</param>
        public static void CreateTranslation(float xPosition, float yPosition, float zPosition, out Matrix result)
        {
            result = Matrix.Identity;

            result.M41 = xPosition;
            result.M42 = yPosition;
            result.M43 = zPosition;
        }
        /// <summary>
        /// Creates a translation Matrix.
        /// </summary>
        /// <param name="xPosition">Value to translate by on the x-axis.</param>
        /// <param name="yPosition">Value to translate by on the y-axis.</param>
        /// <param name="zPosition">Value to translate by on the z-axis.</param>
        public static Matrix CreateTranslation(float xPosition, float yPosition, float zPosition)
        {
            Matrix returnMatrix = Matrix.Identity;

            returnMatrix.M41 = xPosition;
            returnMatrix.M42 = yPosition;
            returnMatrix.M43 = zPosition;

            return returnMatrix;
        }
        /// <summary>
        /// Creates a translation Matrix.
        /// </summary>
        /// <param name="position">Amounts to translate by on the x, y, and z axes.</param>
        /// <param name="result">The created translation Matrix.</param>
        public static void CreateTranslation(ref Vector3 position, out Matrix result)
        {
            result = Matrix.Identity;

            result.M41 = position.X;
            result.M42 = position.Y;
            result.M43 = position.Z;
        }
        /// <summary>
        /// Creates a translation Matrix.
        /// </summary>
        /// <param name="position">Amounts to translate by on the x, y, and z axes.</param>
        public static Matrix CreateTranslation(Vector3 position)
        {
            Matrix returnMatrix = Matrix.Identity;

            returnMatrix.M41 = position.X;
            returnMatrix.M42 = position.Y;
            returnMatrix.M43 = position.Z;

            return returnMatrix;
        }
        /// <summary>
        /// Creates a world matrix with the specified parameters.
        /// </summary>
        /// <param name="position">Position of the object. This value is used in translation operations.</param>
        /// <param name="forward">Forward direction of the object.</param>
        /// <param name="up">Upward direction of the object; usually [0, 1, 0].</param>
        /// <param name="result">The created world matrix.</param>
        public static void CreateWorld(ref Vector3 position, ref Vector3 forward, ref Vector3 up, out Matrix result)
        {
            Vector3 x, y, z;
            Vector3.Normalize(ref forward, out z);
            Vector3.Cross(ref forward, ref up, out x);
            Vector3.Cross(ref x, ref forward, out y);
            x.Normalize();
            y.Normalize();

            result = new Matrix();
            result.Right = x;
            result.Up = y;
            result.Forward = z;
            result.Translation = position;
            result.M44 = 1f;
        }
        /// <summary>
        /// Creates a world matrix with the specified parameters.
        /// </summary>
        /// <param name="position">Position of the object. This value is used in translation operations.</param>
        /// <param name="forward">Forward direction of the object.</param>
        /// <param name="up">Upward direction of the object; usually [0, 1, 0].</param>
        public static Matrix CreateWorld(Vector3 position, Vector3 forward, Vector3 up)
        {
            Matrix result;
            Vector3 x, y, z;
            Vector3.Normalize(ref forward, out z);
            Vector3.Cross(ref forward, ref up, out x);
            Vector3.Cross(ref x, ref forward, out y);
            x.Normalize();
            y.Normalize();

            result = new Matrix();
            result.Right = x;
            result.Up = y;
            result.Forward = z;
            result.Translation = position;
            result.M44 = 1f;
            return result;
        }
        /// <summary>
        /// Extracts the scalar, translation, and rotation components from a 3D scale/rotate/translate (SRT) Matrix.
        /// </summary>
        /// <param name="scale">The scalar component of the transform matrix, expressed as a Vector3.</param>
        /// <param name="rotation">The rotation component of the transform matrix, expressed as a Quaternion.</param>
        /// <param name="translation">The translation component of the transform matrix, expressed as a Vector3.</param>
        public bool Decompose(out Vector3 scale, out Quaternion rotation, out Vector3 translation)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Calculates the determinant of the matrix.
        /// </summary>
        public float Determinant()
        {
            float minor1, minor2, minor3, minor4, minor5, minor6;

            minor1 = M31 * M42 - M32 * M41;
            minor2 = M31 * M43 - M33 * M41;
            minor3 = M31 * M44 - M34 * M41;
            minor4 = M32 * M43 - M33 * M42;
            minor5 = M32 * M44 - M34 * M42;
            minor6 = M33 * M44 - M34 * M43;

            return M11 * (M22 * minor6 - M23 * minor5 + M24 * minor4) -
                            M12 * (M21 * minor6 - M23 * minor3 + M24 * minor2) +
                            M13 * (M21 * minor5 - M22 * minor3 + M24 * minor1) -
                            M14 * (M21 * minor4 - M22 * minor2 + M23 * minor1);
        }
        /// <summary>
        /// Divides the components of a matrix by a scalar.
        /// </summary>
        /// <param name="matrix1">Source matrix.</param>
        /// <param name="divider">The divisor.</param>
        /// <param name="result">Result of the division.</param>
        public static void Divide(ref Matrix matrix1, float divider, out Matrix result)
        {
            float inverseDivider = 1f / divider;
            Matrix.Multiply(ref matrix1, inverseDivider, out result);
        }
        /// <summary>
        /// Divides the components of a matrix by a scalar.
        /// </summary>
        /// <param name="matrix1">Source matrix.</param>
        /// <param name="divider">The divisor.</param>
        public static Matrix Divide(Matrix matrix1, float divider)
        {
            Matrix ret;
            Divide(ref matrix1, divider, out ret);
            return ret;
        }
        /// <summary>
        /// Divides the components of a matrix by the corresponding components of another matrix.
        /// </summary>
        /// <param name="matrix1">Source matrix.</param>
        /// <param name="matrix2">The divisor.</param>
        /// <param name="result">Result of the division.</param>
        public static void Divide(ref Matrix matrix1, ref Matrix matrix2, out Matrix result)
        {
            Matrix inverse = Matrix.Invert(matrix2);
            Matrix.Multiply(ref matrix1, ref inverse, out result);
        }
        /// <summary>
        /// Divides the components of a matrix by the corresponding components of another matrix.
        /// </summary>
        /// <param name="matrix1">Source matrix.</param>
        /// <param name="matrix2">The divisor.</param>
        public static Matrix Divide(Matrix matrix1, Matrix matrix2)
        {
            Matrix ret;
            Matrix.Divide(ref matrix1, ref matrix2, out ret);
            return ret;
        }
        /// <summary>
        /// Returns a value that indicates whether the current instance is equal to a specified object.
        /// </summary>
        /// <param name="obj">Object with which to make the comparison.</param>
        public override bool Equals(object obj)
        {
            return this == (Matrix)obj;
        } 
        /// <summary>
        /// Determines whether the specified Object is equal to the Matrix.
        /// </summary>
        /// <param name="other">The Object to compare with the current Matrix.</param>
        public bool Equals(Matrix other)
        {
            return this == other;
        }
        /// <summary>
        /// Gets the hash code of this object.
        /// </summary>
        public override int GetHashCode()
        {
            return M11.GetHashCode() + M12.GetHashCode() + M13.GetHashCode() + M14.GetHashCode() +
                            M21.GetHashCode() + M22.GetHashCode() + M23.GetHashCode() + M24.GetHashCode() +
                            M31.GetHashCode() + M32.GetHashCode() + M33.GetHashCode() + M34.GetHashCode() +
                            M41.GetHashCode() + M42.GetHashCode() + M43.GetHashCode() + M44.GetHashCode(); 
        }
        /// <summary>
        /// Calculates the inverse of a matrix.
        /// </summary>
        /// <param name="matrix">The source matrix.</param>
        /// <param name="result">The inverse of matrix. The same matrix can be used for both arguments.</param>
        public static void Invert(ref Matrix matrix, out Matrix result)
        {
            /// 
            // Use Laplace expansion theorem to calculate the inverse of a 4x4 matrix 
            //  
            // 1. Calculate the 2x2 determinants needed and the 4x4 determinant based on the 2x2 determinants  
            // 3. Create the adjugate matrix, which satisfies: A * adj(A) = det(A) * I 
            // 4. Divide adjugate matrix with the determinant to find the inverse 
            float det1 = matrix.M11 * matrix.M22 - matrix.M12 * matrix.M21;
            float det2 = matrix.M11 * matrix.M23 - matrix.M13 * matrix.M21;
            float det3 = matrix.M11 * matrix.M24 - matrix.M14 * matrix.M21;
            float det4 = matrix.M12 * matrix.M23 - matrix.M13 * matrix.M22;
            float det5 = matrix.M12 * matrix.M24 - matrix.M14 * matrix.M22;
            float det6 = matrix.M13 * matrix.M24 - matrix.M14 * matrix.M23;
            float det7 = matrix.M31 * matrix.M42 - matrix.M32 * matrix.M41;
            float det8 = matrix.M31 * matrix.M43 - matrix.M33 * matrix.M41;
            float det9 = matrix.M31 * matrix.M44 - matrix.M34 * matrix.M41;
            float det10 = matrix.M32 * matrix.M43 - matrix.M33 * matrix.M42;
            float det11 = matrix.M32 * matrix.M44 - matrix.M34 * matrix.M42;
            float det12 = matrix.M33 * matrix.M44 - matrix.M34 * matrix.M43;

            float detMatrix = (float)(det1 * det12 - det2 * det11 + det3 * det10 + det4 * det9 - det5 * det8 + det6 * det7);

            float invDetMatrix = 1f / detMatrix;

            Matrix ret; // Allow for matrix and result to point to the same structure 

            ret.M11 = (matrix.M22 * det12 - matrix.M23 * det11 + matrix.M24 * det10) * invDetMatrix;
            ret.M12 = (-matrix.M12 * det12 + matrix.M13 * det11 - matrix.M14 * det10) * invDetMatrix;
            ret.M13 = (matrix.M42 * det6 - matrix.M43 * det5 + matrix.M44 * det4) * invDetMatrix;
            ret.M14 = (-matrix.M32 * det6 + matrix.M33 * det5 - matrix.M34 * det4) * invDetMatrix;
            ret.M21 = (-matrix.M21 * det12 + matrix.M23 * det9 - matrix.M24 * det8) * invDetMatrix;
            ret.M22 = (matrix.M11 * det12 - matrix.M13 * det9 + matrix.M14 * det8) * invDetMatrix;
            ret.M23 = (-matrix.M41 * det6 + matrix.M43 * det3 - matrix.M44 * det2) * invDetMatrix;
            ret.M24 = (matrix.M31 * det6 - matrix.M33 * det3 + matrix.M34 * det2) * invDetMatrix;
            ret.M31 = (matrix.M21 * det11 - matrix.M22 * det9 + matrix.M24 * det7) * invDetMatrix;
            ret.M32 = (-matrix.M11 * det11 + matrix.M12 * det9 - matrix.M14 * det7) * invDetMatrix;
            ret.M33 = (matrix.M41 * det5 - matrix.M42 * det3 + matrix.M44 * det1) * invDetMatrix;
            ret.M34 = (-matrix.M31 * det5 + matrix.M32 * det3 - matrix.M34 * det1) * invDetMatrix;
            ret.M41 = (-matrix.M21 * det10 + matrix.M22 * det8 - matrix.M23 * det7) * invDetMatrix;
            ret.M42 = (matrix.M11 * det10 - matrix.M12 * det8 + matrix.M13 * det7) * invDetMatrix;
            ret.M43 = (-matrix.M41 * det4 + matrix.M42 * det2 - matrix.M43 * det1) * invDetMatrix;
            ret.M44 = (matrix.M31 * det4 - matrix.M32 * det2 + matrix.M33 * det1) * invDetMatrix;

            result = ret;
        }
        /// <summary>
        /// Calculates the inverse of a matrix.
        /// </summary>
        /// <param name="matrix">The source matrix.</param>
        public static Matrix Invert(Matrix matrix)
        {
            Invert(ref matrix, out matrix);
            return matrix;
        }
        /// <summary>
        /// Linearly interpolates between the corresponding values of two matrices.
        /// </summary>
        /// <param name="matrix1">Source matrix.</param>
        /// <param name="matrix2">Source matrix.</param>
        /// <param name="amount">Interpolation value.</param>
        /// <param name="result">Resulting matrix.</param>
        public static void Lerp(ref Matrix matrix1, ref Matrix matrix2, float amount, out Matrix result)
        {
            result.M11 = MathHelper.Lerp(matrix1.M11, matrix2.M11, amount);
            result.M12 = MathHelper.Lerp(matrix1.M12, matrix2.M12, amount);
            result.M13 = MathHelper.Lerp(matrix1.M13, matrix2.M13, amount);
            result.M14 = MathHelper.Lerp(matrix1.M14, matrix2.M14, amount);
            result.M21 = MathHelper.Lerp(matrix1.M21, matrix2.M21, amount);
            result.M22 = MathHelper.Lerp(matrix1.M22, matrix2.M22, amount);
            result.M23 = MathHelper.Lerp(matrix1.M23, matrix2.M23, amount);
            result.M24 = MathHelper.Lerp(matrix1.M24, matrix2.M24, amount);
            result.M31 = MathHelper.Lerp(matrix1.M31, matrix2.M31, amount);
            result.M32 = MathHelper.Lerp(matrix1.M32, matrix2.M32, amount);
            result.M33 = MathHelper.Lerp(matrix1.M33, matrix2.M33, amount);
            result.M34 = MathHelper.Lerp(matrix1.M34, matrix2.M34, amount);
            result.M41 = MathHelper.Lerp(matrix1.M41, matrix2.M41, amount);
            result.M42 = MathHelper.Lerp(matrix1.M42, matrix2.M42, amount);
            result.M43 = MathHelper.Lerp(matrix1.M43, matrix2.M43, amount);
            result.M44 = MathHelper.Lerp(matrix1.M44, matrix2.M44, amount);
        }
        /// <summary>
        /// Linearly interpolates between the corresponding values of two matrices.
        /// </summary>
        /// <param name="matrix1">Source matrix.</param>
        /// <param name="matrix2">Source matrix.</param>
        /// <param name="amount">Interpolation value.</param>
        public static Matrix Lerp(Matrix matrix1, Matrix matrix2, float amount)
        {
            Matrix result;
            result.M11 = MathHelper.Lerp(matrix1.M11, matrix2.M11, amount);
            result.M12 = MathHelper.Lerp(matrix1.M12, matrix2.M12, amount);
            result.M13 = MathHelper.Lerp(matrix1.M13, matrix2.M13, amount);
            result.M14 = MathHelper.Lerp(matrix1.M14, matrix2.M14, amount);
            result.M21 = MathHelper.Lerp(matrix1.M21, matrix2.M21, amount);
            result.M22 = MathHelper.Lerp(matrix1.M22, matrix2.M22, amount);
            result.M23 = MathHelper.Lerp(matrix1.M23, matrix2.M23, amount);
            result.M24 = MathHelper.Lerp(matrix1.M24, matrix2.M24, amount);
            result.M31 = MathHelper.Lerp(matrix1.M31, matrix2.M31, amount);
            result.M32 = MathHelper.Lerp(matrix1.M32, matrix2.M32, amount);
            result.M33 = MathHelper.Lerp(matrix1.M33, matrix2.M33, amount);
            result.M34 = MathHelper.Lerp(matrix1.M34, matrix2.M34, amount);
            result.M41 = MathHelper.Lerp(matrix1.M41, matrix2.M41, amount);
            result.M42 = MathHelper.Lerp(matrix1.M42, matrix2.M42, amount);
            result.M43 = MathHelper.Lerp(matrix1.M43, matrix2.M43, amount);
            result.M44 = MathHelper.Lerp(matrix1.M44, matrix2.M44, amount);
            return result;
        }
        /// <summary>
        /// Multiplies a matrix by a scalar value.
        /// </summary>
        /// <param name="matrix1">Source matrix.</param>
        /// <param name="factor">Scalar value.</param>
        /// <param name="result">The result of the multiplication.</param>
        public static void Multiply(ref Matrix matrix1, float factor, out Matrix result)
        {
            result.M11 = matrix1.M11 * factor;
            result.M12 = matrix1.M12 * factor;
            result.M13 = matrix1.M13 * factor;
            result.M14 = matrix1.M14 * factor;
            result.M21 = matrix1.M21 * factor;
            result.M22 = matrix1.M22 * factor;
            result.M23 = matrix1.M23 * factor;
            result.M24 = matrix1.M24 * factor;
            result.M31 = matrix1.M31 * factor;
            result.M32 = matrix1.M32 * factor;
            result.M33 = matrix1.M33 * factor;
            result.M34 = matrix1.M34 * factor;
            result.M41 = matrix1.M41 * factor;
            result.M42 = matrix1.M42 * factor;
            result.M43 = matrix1.M43 * factor;
            result.M44 = matrix1.M44 * factor;
        }
        /// <summary>
        /// Multiplies a matrix by a scalar value.
        /// </summary>
        /// <param name="matrix1">Source matrix.</param>
        /// <param name="factor">Scalar value.</param>
        public static Matrix Multiply(Matrix matrix1, float factor)
        {
            matrix1.M11 *= factor;
            matrix1.M12 *= factor;
            matrix1.M13 *= factor;
            matrix1.M14 *= factor;
            matrix1.M21 *= factor;
            matrix1.M22 *= factor;
            matrix1.M23 *= factor;
            matrix1.M24 *= factor;
            matrix1.M31 *= factor;
            matrix1.M32 *= factor;
            matrix1.M33 *= factor;
            matrix1.M34 *= factor;
            matrix1.M41 *= factor;
            matrix1.M42 *= factor;
            matrix1.M43 *= factor;
            matrix1.M44 *= factor;
            return matrix1;
        } 
        /// <summary>
        /// Multiplies a matrix by another matrix.
        /// </summary>
        /// <param name="matrix1">Source matrix.</param>
        /// <param name="matrix2">Source matrix.</param>
        /// <param name="result">Result of the multiplication.</param>
        public static void Multiply(ref Matrix matrix1, ref Matrix matrix2, out Matrix result)
        {
            result.M11 = matrix1.M11 * matrix2.M11 + matrix1.M12 * matrix2.M21 + matrix1.M13 * matrix2.M31 + matrix1.M14 * matrix2.M41;
            result.M12 = matrix1.M11 * matrix2.M12 + matrix1.M12 * matrix2.M22 + matrix1.M13 * matrix2.M32 + matrix1.M14 * matrix2.M42;
            result.M13 = matrix1.M11 * matrix2.M13 + matrix1.M12 * matrix2.M23 + matrix1.M13 * matrix2.M33 + matrix1.M14 * matrix2.M43;
            result.M14 = matrix1.M11 * matrix2.M14 + matrix1.M12 * matrix2.M24 + matrix1.M13 * matrix2.M34 + matrix1.M14 * matrix2.M44;

            result.M21 = matrix1.M21 * matrix2.M11 + matrix1.M22 * matrix2.M21 + matrix1.M23 * matrix2.M31 + matrix1.M24 * matrix2.M41;
            result.M22 = matrix1.M21 * matrix2.M12 + matrix1.M22 * matrix2.M22 + matrix1.M23 * matrix2.M32 + matrix1.M24 * matrix2.M42;
            result.M23 = matrix1.M21 * matrix2.M13 + matrix1.M22 * matrix2.M23 + matrix1.M23 * matrix2.M33 + matrix1.M24 * matrix2.M43;
            result.M24 = matrix1.M21 * matrix2.M14 + matrix1.M22 * matrix2.M24 + matrix1.M23 * matrix2.M34 + matrix1.M24 * matrix2.M44;

            result.M31 = matrix1.M31 * matrix2.M11 + matrix1.M32 * matrix2.M21 + matrix1.M33 * matrix2.M31 + matrix1.M34 * matrix2.M41;
            result.M32 = matrix1.M31 * matrix2.M12 + matrix1.M32 * matrix2.M22 + matrix1.M33 * matrix2.M32 + matrix1.M34 * matrix2.M42;
            result.M33 = matrix1.M31 * matrix2.M13 + matrix1.M32 * matrix2.M23 + matrix1.M33 * matrix2.M33 + matrix1.M34 * matrix2.M43;
            result.M34 = matrix1.M31 * matrix2.M14 + matrix1.M32 * matrix2.M24 + matrix1.M33 * matrix2.M34 + matrix1.M34 * matrix2.M44;

            result.M41 = matrix1.M41 * matrix2.M11 + matrix1.M42 * matrix2.M21 + matrix1.M43 * matrix2.M31 + matrix1.M44 * matrix2.M41;
            result.M42 = matrix1.M41 * matrix2.M12 + matrix1.M42 * matrix2.M22 + matrix1.M43 * matrix2.M32 + matrix1.M44 * matrix2.M42;
            result.M43 = matrix1.M41 * matrix2.M13 + matrix1.M42 * matrix2.M23 + matrix1.M43 * matrix2.M33 + matrix1.M44 * matrix2.M43;
            result.M44 = matrix1.M41 * matrix2.M14 + matrix1.M42 * matrix2.M24 + matrix1.M43 * matrix2.M34 + matrix1.M44 * matrix2.M44;
        }
        /// <summary>
        /// Multiplies a matrix by another matrix.
        /// </summary>
        /// <param name="matrix1">Source matrix.</param>
        /// <param name="matrix2">Source matrix.</param>
        public static Matrix Multiply(Matrix matrix1, Matrix matrix2)
        {
            Matrix ret;
            Multiply(ref matrix1, ref matrix2, out ret);
            return ret;
        }
        /// <summary>
        /// Negates individual elements of a matrix.
        /// </summary>
        /// <param name="matrix">Source matrix.</param>
        /// <param name="result">Negated matrix.</param>
        public static void Negate(ref Matrix matrix, out Matrix result)
        {
            Matrix.Multiply(ref matrix, -1.0f, out result);
        }
        /// <summary>
        /// Negates individual elements of a matrix.
        /// </summary>
        /// <param name="matrix">Source matrix.</param>
        public static Matrix Negate(Matrix matrix)
        {
            Matrix.Multiply(ref matrix, -1.0f, out matrix);
            return matrix;
        }
        /// <summary>
        /// Subtracts matrices.
        /// </summary>
        /// <param name="matrix1">Source matrix.</param>
        /// <param name="matrix2">Source matrix.</param>
        /// <param name="result">Result of the subtraction.</param>
        public static void Subtract(ref Matrix matrix1, ref Matrix matrix2, out Matrix result)
        {
            result.M11 = matrix1.M11 - matrix2.M11;
            result.M12 = matrix1.M12 - matrix2.M12;
            result.M13 = matrix1.M13 - matrix2.M13;
            result.M14 = matrix1.M14 - matrix2.M14;
            result.M21 = matrix1.M21 - matrix2.M21;
            result.M22 = matrix1.M22 - matrix2.M22;
            result.M23 = matrix1.M23 - matrix2.M23;
            result.M24 = matrix1.M24 - matrix2.M24;
            result.M31 = matrix1.M31 - matrix2.M31;
            result.M32 = matrix1.M32 - matrix2.M32;
            result.M33 = matrix1.M33 - matrix2.M33;
            result.M34 = matrix1.M34 - matrix2.M34;
            result.M41 = matrix1.M41 - matrix2.M41;
            result.M42 = matrix1.M42 - matrix2.M42;
            result.M43 = matrix1.M43 - matrix2.M43;
            result.M44 = matrix1.M44 - matrix2.M44;
        }
        /// <summary>
        /// Subtracts matrices.
        /// </summary>
        /// <param name="matrix1">Source matrix.</param>
        /// <param name="matrix2">Source matrix.</param>
        /// <returns></returns>
        public static Matrix Subtract(Matrix matrix1, Matrix matrix2)
        {
            matrix1.M11 -= matrix2.M11;
            matrix1.M12 -= matrix2.M12;
            matrix1.M13 -= matrix2.M13;
            matrix1.M14 -= matrix2.M14;
            matrix1.M21 -= matrix2.M21;
            matrix1.M22 -= matrix2.M22;
            matrix1.M23 -= matrix2.M23;
            matrix1.M24 -= matrix2.M24;
            matrix1.M31 -= matrix2.M31;
            matrix1.M32 -= matrix2.M32;
            matrix1.M33 -= matrix2.M33;
            matrix1.M34 -= matrix2.M34;
            matrix1.M41 -= matrix2.M41;
            matrix1.M42 -= matrix2.M42;
            matrix1.M43 -= matrix2.M43;
            matrix1.M44 -= matrix2.M44;
            return matrix1;
        }
        /// <summary>
        /// Retrieves a string representation of the current object.
        /// </summary>
        public override string ToString()
        {
            return "{ {M11:" + M11 + " M12:" + M12 + " M13:" + M13 + " M14:" + M14 + "}" +
                    " {M21:" + M21 + " M22:" + M22 + " M23:" + M23 + " M24:" + M24 + "}" +
                    " {M31:" + M31 + " M32:" + M32 + " M33:" + M33 + " M34:" + M34 + "}" +
                    " {M41:" + M41 + " M42:" + M42 + " M43:" + M43 + " M44:" + M44 + "} }";
        }
        /// <summary>
        /// Transforms a Matrix by applying a Quaternion rotation.
        /// </summary>
        /// <param name="value">The Matrix to transform.</param>
        /// <param name="rotation">The rotation to apply, expressed as a Quaternion.</param>
        /// <param name="result">An existing Matrix filled in with the result of the transform.</param>
        public static void Transform(ref Matrix value, ref Quaternion rotation, out Matrix result)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Transforms a Matrix by applying a Quaternion rotation.
        /// </summary>
        /// <param name="value">The Matrix to transform.</param>
        /// <param name="rotation">The rotation to apply, expressed as a Quaternion.</param>
        public static Matrix Transform(Matrix value, Quaternion rotation)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Transposes the rows and columns of a matrix.
        /// </summary>
        /// <param name="matrix">Source matrix.</param>
        /// <param name="result">Transposed matrix.</param>
        public static void Transpose(ref Matrix matrix, out Matrix result)
        {
            result.M11 = matrix.M11;
            result.M12 = matrix.M21;
            result.M13 = matrix.M31;
            result.M14 = matrix.M41;

            result.M21 = matrix.M12;
            result.M22 = matrix.M22;
            result.M23 = matrix.M32;
            result.M24 = matrix.M42;

            result.M31 = matrix.M13;
            result.M32 = matrix.M23;
            result.M33 = matrix.M33;
            result.M34 = matrix.M43;

            result.M41 = matrix.M14;
            result.M42 = matrix.M24;
            result.M43 = matrix.M34;
            result.M44 = matrix.M44;
        }
        /// <summary>
        /// Transposes the rows and columns of a matrix.
        /// </summary>
        /// <param name="matrix">Source matrix.</param>
        public static Matrix Transpose(Matrix matrix)
        {
            Matrix ret;
            Transpose(ref matrix, out ret);
            return ret;
        } 
        #endregion

        #region Operators
        /// <summary>
        /// Subtracts matrices.
        /// </summary>
        /// <param name="matrix1">Source matrix.</param>
        /// <param name="matrix2">Source matrix.</param>
        public static Matrix operator -(Matrix matrix1, Matrix matrix2)
        {
            Matrix returnMatrix = new Matrix();
            Matrix.Subtract(ref matrix1, ref matrix2, out returnMatrix);
            return returnMatrix;
        }
        /// <summary>
        /// Negates individual elements of a matrix.
        /// </summary>
        /// <param name="matrix1">Source matrix.</param>
        public static Matrix operator -(Matrix matrix1)
        {
            Matrix.Negate(ref matrix1, out matrix1);
            return matrix1;
        }
        /// <summary>
        /// Tests a matrix for inequality with another matrix.
        /// </summary>
        /// <param name="matrix1">The matrix on the left of the equal sign.</param>
        /// <param name="matrix2">The matrix on the right of the equal sign.</param>
        public static bool operator !=(Matrix matrix1, Matrix matrix2)
        {
            return !(matrix1 == matrix2);
        }
        /// <summary>
        /// Multiplies a matrix by a scalar value.
        /// </summary>
        /// <param name="scaleFactor">Scalar value.</param>
        /// <param name="matrix">Source matrix.</param>
        public static Matrix operator *(float scaleFactor, Matrix matrix)
        {
            Matrix target;
            target.M11 = matrix.M11 * scaleFactor;
            target.M12 = matrix.M12 * scaleFactor;
            target.M13 = matrix.M13 * scaleFactor;
            target.M14 = matrix.M14 * scaleFactor;
            target.M21 = matrix.M21 * scaleFactor;
            target.M22 = matrix.M22 * scaleFactor;
            target.M23 = matrix.M23 * scaleFactor;
            target.M24 = matrix.M24 * scaleFactor;
            target.M31 = matrix.M31 * scaleFactor;
            target.M32 = matrix.M32 * scaleFactor;
            target.M33 = matrix.M33 * scaleFactor;
            target.M34 = matrix.M34 * scaleFactor;
            target.M41 = matrix.M41 * scaleFactor;
            target.M42 = matrix.M42 * scaleFactor;
            target.M43 = matrix.M43 * scaleFactor;
            target.M44 = matrix.M44 * scaleFactor;
            return target;
        }
        /// <summary>
        /// Multiplies a matrix by a scalar value.
        /// </summary>
        /// <param name="matrix">Source matrix.</param>
        /// <param name="scaleFactor">Scalar value.</param>
        public static Matrix operator *(Matrix matrix, float scaleFactor)
        {
            Matrix.Multiply(ref matrix, scaleFactor, out matrix);
            return matrix;
        }
        /// <summary>
        /// Multiplies a matrix by another matrix.
        /// </summary>
        /// <param name="matrix1">Source matrix.</param>
        /// <param name="matrix2">Source matrix.</param>
        public static Matrix operator *(Matrix matrix1, Matrix matrix2)
        {
            Matrix returnMatrix = new Matrix();
            Matrix.Multiply(ref matrix1, ref matrix2, out returnMatrix);
            return returnMatrix;
        }
        /// <summary>
        /// Divides the components of a matrix by a scalar.
        /// </summary>
        /// <param name="matrix1">Source matrix.</param>
        /// <param name="divider">The divisor.</param>
        public static Matrix operator /(Matrix matrix1, float divider)
        {
            Matrix ret;
            Matrix.Divide(ref matrix1, divider, out ret);
            return ret;
        }
        /// <summary>
        /// Divides the components of a matrix by the corresponding components of another matrix.
        /// </summary>
        /// <param name="matrix1">Source matrix.</param>
        /// <param name="matrix2">The divisor.</param>
        public static Matrix operator /(Matrix matrix1, Matrix matrix2)
        {
            Matrix ret;
            Matrix.Divide(ref matrix1, ref matrix2, out ret);
            return ret;
        }
        /// <summary>
        /// Adds a matrix to another matrix.
        /// </summary>
        /// <param name="matrix1">Source matrix.</param>
        /// <param name="matrix2">Source matrix.</param>
        public static Matrix operator +(Matrix matrix1, Matrix matrix2)
        {
            Matrix.Add(ref matrix1, ref matrix2, out matrix1);
            return matrix1;
        }
        /// <summary>
        /// Compares a matrix for equality with another matrix.
        /// </summary>
        /// <param name="matrix1">Source matrix.</param>
        /// <param name="matrix2">Source matrix.</param>
        public static bool operator ==(Matrix matrix1, Matrix matrix2)
        {
            return (matrix1.M11 == matrix2.M11) && (matrix1.M12 == matrix2.M12) &&
                   (matrix1.M13 == matrix2.M13) && (matrix1.M14 == matrix2.M14) &&
                   (matrix1.M21 == matrix2.M21) && (matrix1.M22 == matrix2.M22) &&
                   (matrix1.M23 == matrix2.M23) && (matrix1.M24 == matrix2.M24) &&
                   (matrix1.M31 == matrix2.M31) && (matrix1.M32 == matrix2.M32) &&
                   (matrix1.M33 == matrix2.M33) && (matrix1.M34 == matrix2.M34) &&
                   (matrix1.M41 == matrix2.M41) && (matrix1.M42 == matrix2.M42) &&
                   (matrix1.M43 == matrix2.M43) && (matrix1.M44 == matrix2.M44);
        } 
        #endregion
    }
}
